<?php
class system_controller_action_helper_redirector extends system_controller_action_helper_abstract {
	protected $_code = 302;
	protected $_exit = true;
	protected $_prependBase = true;
	protected $_redirectUrl = null;
	protected $_useAbsoluteUri = false; //是否使用绝对地址
	protected $_closeSessionOnExit = true;
	
	public function getCode() {
		return $this->_code;
	}
	protected function _checkCode($code) {
		$code = (int) $code;
		if((300 > $code) || (307 < $code) || (304 == $code) || (306 == $code)) {
			throw new system_exception('Invalid redirect HTTP status code (' . $code . ')');
		}
		return true;
	}
	
	public function setCode($code) {
		$this->_checkCode($code);
		$this->_code = $code;
		return $this;
	}
	public function getExit() {
		return $this->_exit;
	}
	
	public function setExit($flag) {
		$this->_exit = ($flag) ? true : false;
		return $this;
	}
	
	public function getPrependBase() {
		return $this->_prependBase;
	}
	
	public function setPrependBase($flag) {
		$this->_prependBase = ($flag) ? true : false;
		return $this;
	}
	
	public function getCloseSessionOnExit() {
		return $this->_closeSessionOnExit;
	}
	
	public function setCloseSessionOnExit($flag) {
		$this->_closeSessionOnExit = ($flag) ? true : false;
		return $this;
	}
	
	public function getUseAbsoluteUri() {
		return $this->_useAbsoluteUri;
	}
	public function setUseAbsoluteUri($flag = true) {
		$this->_useAbsoluteUri = ($flag) ? true : false;
		return $this;
	}
	
	protected function _redirect($url) {
		if($this->getUseAbsoluteUri() && !preg_match('#^(https?|ftp)://#', $url)) {
			$host = (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : '');
			$proto = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== "off") ? 'https' : 'http';
			$port = (isset($_SERVER['SERVER_PORT']) ? $_SERVER['SERVER_PORT'] : 80);
			$uri = $proto . '://' . $host;
			if((('http' == $proto) && (80 != $port)) || (('https' == $proto) && (443 != $port))) {
				// do not append if HTTP_HOST already contains port
				if(strrchr($host, ':') === false) {
					$uri .= ':' . $port;
				}
			}
			$url = $uri . '/' . ltrim($url, '/');
		}
		$this->_redirectUrl = $url;
		$this->getResponse()->setRedirect($url, $this->getCode());
	}
	public function getRedirectUrl() {
		return $this->_redirectUrl;
	}
	protected function _prependBase($url) {
		if($this->getPrependBase()) {
			$request = $this->getRequest();
			if($request instanceof system_controller_request_Http) {
				$base = rtrim($request->getBaseUrl(), '/');
				if(!empty($base) && ('/' != $base)) {
					$url = $base . '/' . ltrim($url, '/');
				} else {
					$url = '/' . ltrim($url, '/');
				}
			}
		}
		
		return $url;
	}
	
	public function setGotoRoute($name, array $urlOptions = array(), $reset = false, $encode = true) {
		$router = $this->getFrontController()->getRouter();
		$url = $router->assemble($name, $urlOptions, $reset, $encode);
		$this->_redirect($url);
	}
	
	public function setGotoUrl($url, array $options = array()) {
		// prevent header injections
		$url = str_replace(array("\n", "\r"), '', $url);
		
		if(null !== $options) {
			if(isset($options['exit'])) {
				$this->setExit(($options['exit']) ? true : false);
			}
			if(isset($options['prependBase'])) {
				$this->setPrependBase(($options['prependBase']) ? true : false);
			}
			if(isset($options['code'])) {
				$this->setCode($options['code']);
			}
		}

		// If relative URL, decide if we should prepend base URL
		if(!preg_match('|^[a-z]+://|', $url)) {
			$url = $this->_prependBase($url);
		}
		$this->_redirect($url);
	}
	
	public function gotoRoute($name = null, array $urlOptions = array(), $reset = false, $encode = true) {
		$this->setGotoRoute($name, $urlOptions, $reset, $encode);
		
		if($this->getExit()) {
			$this->redirectAndExit();
		}
	}
	public function gotoRouteAndExit($name, array $urlOptions = array(), $reset = false) {
		$this->setGotoRoute($name, $urlOptions, $reset);
		$this->redirectAndExit();
	}
	
	public function gotoUrl($url, array $options = array()) {
		$this->setGotoUrl($url, $options);
		if($this->getExit()) {
			$this->redirectAndExit();
		}
	}
	public function gotoUrlAndExit($url, array $options = array()) {
		$this->setGotoUrl($url, $options);
		$this->redirectAndExit();
	}
	public function redirectAndExit() {
		if($this->getCloseSessionOnExit()) {
			// Close session, if started
		}
		
		$this->getResponse()->sendHeaders();
		exit();
	}
	public function direct($args = array()) {
		return $this;
	}
}